﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public class ABManager : Singleton<ABManager>
{

    /// <summary>
    /// 资源关系依赖表 可以根据crc 来找到对应的资源块
    /// </summary>
    protected Dictionary<uint, ResourceItem> m_resourceItemDic = new Dictionary<uint, ResourceItem>();
    /// <summary>
    /// AssetBundle资源 管理加载和卸载 key为crc
    /// </summary>
    protected Dictionary<uint, AssetBundleItem> m_assetBundleItemDic = new Dictionary<uint, AssetBundleItem>();
    /// <summary>
    /// AssetbundleItem对象池
    /// </summary>
    protected ClassObjectPool<AssetBundleItem> m_assetBundleItemPool = ObjectManager.Instance.GetOrCreateClassPool<AssetBundleItem>(500);
   
    /// <summary>
    /// 加载AB 配置表
    /// </summary>
    /// <returns></returns>
    public bool LoadAssetBundleConfig()
    {
        string configpath = Application.streamingAssetsPath + "/AssetBundles/assetbundleconfig";
        AssetBundle confingAB = AssetBundle.LoadFromFile(configpath);
        TextAsset textAsset = confingAB.LoadAsset<TextAsset>("AssetBundleConfig");
        if (textAsset==null)
        {
            Debug.LogError("AssetBundleConfig is  not exit");
            return false;
        }

        ///反序列化二进制数据
        MemoryStream stream = new MemoryStream(textAsset.bytes);
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        AssetBundleConfig config =(AssetBundleConfig) binaryFormatter.Deserialize(stream);
        stream.Close();

        for (int i = 0; i < config.ABList.Count; i++)
        {
            ABBase ab = config.ABList[i];
            if (this.m_resourceItemDic.ContainsKey(ab.Crc))
            {
                Debug.LogError("资源crc 重复：包名 "+ab.ABName+" 资源名:"+ab.AssetName);
                continue;
            }
            ResourceItem item = new ResourceItem();
            item.m_Crc = ab.Crc;
            item.m_AssetName = ab.AssetName;
            item.m_ABName = ab.ABName;
            item.m_DependenceBundle = ab.ABDependences;
            this.m_resourceItemDic.Add(item.m_Crc,item);
        }
        return true;
    }


    /// <summary>
    /// 根据路径的Crc 加载ResoureItem
    /// </summary>
    /// <param name="crc"></param>
    /// <returns></returns>
    public ResourceItem LoadResourceAssetBundle(uint crc)
    {
        ResourceItem item = null;
        if (!this.m_resourceItemDic.TryGetValue(crc,out item)||item==null)
        {
            Debug.LogError(string.Format( "LoadResourceAssetBundle error: can not found crc {0} in AssetBundleConfig ",crc.ToString()));
            return item;
        }
        //已经存在assetBundle
        if (item.m_AssetBundle!=null)
            return item;

        item.m_AssetBundle = LoadAssetBundle(item.m_ABName);
        if (item.m_DependenceBundle!=null)
        {
            for (int i = 0; i < item.m_DependenceBundle.Count; i++)
            {
                LoadAssetBundle(item.m_AssetName);
            }
        }
        return item;
    }



    /// <summary>
    /// 卸载ab 根据resourItem
    /// </summary>
    public void ReleaseAssetBundle(ResourceItem item)
    {
        if (item == null) return;
        if (item.m_DependenceBundle!=null)
        {
            for (int i = 0; i < item.m_DependenceBundle.Count; i++)
            {
                UnLoadAssetBundle(item.m_DependenceBundle[i]);
            }
        }
        UnLoadAssetBundle(item.m_ABName);
    }

    /// <summary>
    /// 卸载ab包
    /// </summary>
    /// <param name="abName"></param>
    private void UnLoadAssetBundle(string abName)
    {
        uint crc = Crc32.GetCrc32(abName);
        AssetBundleItem item = null;
        if (m_assetBundleItemDic.TryGetValue(crc, out item)&&item!=null)
        {
            item.UnLoadBundle(()=> {
                m_assetBundleItemPool.Recycle(item);
                m_assetBundleItemDic.Remove(crc);
            });
        }
    }
    /// <summary>
    /// 加载Assetbundle 并对资源引用计数
    /// </summary>
    /// <returns></returns>
    private AssetBundle LoadAssetBundle(string name)
    {
        AssetBundleItem bundleItem = null;
        uint crc = Crc32.GetCrc32(name);
        AssetBundle assetBundle = null;
        if (!m_assetBundleItemDic.TryGetValue(crc,out bundleItem))
        {
            string fullPath = Application.streamingAssetsPath + "/AssetBundles/" + name;
            if (File.Exists(fullPath))
                assetBundle= AssetBundle.LoadFromFile(fullPath);

            if (assetBundle == null)
                Debug.LogError("Load AssetBundle error:" + fullPath);
            bundleItem = m_assetBundleItemPool.Spwan(true);
            bundleItem.SetBundleInfo(assetBundle);
            if (assetBundle != null) m_assetBundleItemDic.Add(crc, bundleItem);
       
        }

        bundleItem.SetBundleInfo(bundleItem.m_AssetBundle);
        return bundleItem.m_AssetBundle;
    }

    /// <summary>
    /// 根据crc 找到ResourceItem 资源
    /// </summary>
    /// <returns></returns>
    public ResourceItem FinResourceItemByCrc(uint crc)
    {
        if (m_resourceItemDic.ContainsKey(crc))
        {
            return m_resourceItemDic[crc];
        }
        else
        {
            Debug.LogError("not found Resource "+crc);
            return null;
        }

    }

}


public class AssetBundleItem
{
    public AssetBundle m_AssetBundle { get; private set; }
    /// <summary>
    /// 被用到引用个数
    /// </summary>
    public int RefCount { get; private set; }

    /// <summary>
    /// 加载资源
    /// </summary>
    /// <param name="bundle"></param>
    public void SetBundleInfo(AssetBundle bundle)
    {
        this.m_AssetBundle = bundle;
        RefCount++;
    }

 

    /// <summary>
    /// 卸载资源
    /// </summary>
    public void UnLoadBundle(System.Action unloadCallBack)
    {
        RefCount--;
        if (RefCount <= 0)
            Reset(unloadCallBack);
          
    }

    /// <summary>
    /// 重置 清除引用个数 清空资源
    /// </summary>
    private void Reset(System.Action unloadCallBack)
    {
        if (this.m_AssetBundle != null)
        {
            this.m_AssetBundle.Unload(true);
            unloadCallBack();
        }  
        m_AssetBundle = null;
        RefCount = 0;
    }

}

public class ResourceItem
{
    public uint m_Crc = 0;
    /// <summary>
    /// 资源文件名
    /// </summary>
    public string m_AssetName = "";
    /// <summary>
    /// 资源所在的Assetbundle名字
    /// </summary>
    public string m_ABName = "";
    /// <summary>
    /// 该资源所依赖的Assetbundle名字
    /// </summary>
    public List<string> m_DependenceBundle = new List<string>();
//=============================================================
    /// <summary>
    /// 该资源所加载完的AB包
    /// </summary>
    public AssetBundle m_AssetBundle = null;
    /// <summary>
    /// 资源对象
    /// </summary>
    public Object m_Obj = null;
    /// <summary>
    /// 资源唯一标识
    /// </summary>
    public int m_Guid;

    /// <summary>
    /// 资源最后使用的时间
    /// </summary>
    public float m_LastUseTime = 0.0f;
    /// <summary>
    /// 跳场景的时候是否需要清除掉
    /// </summary>
    public bool m_Clear = true;

    protected int m_refCount;
    /// <summary>
    /// 引用计数
    /// </summary>
    public int RefCount
    {
        get { return this.m_refCount; }
        set
        {
            m_refCount = value;
            if (m_refCount<0)
            {
                Debug.LogError("m_refCount<0 "+ m_refCount+" "+(m_Obj!=null?m_Obj.name: "name is null"));
            }
        }
    }
       

}